<?php

/**
 * Model che rappresenta un cliente nel DB.
 */
class Cliente extends StdModel
{

	private static $singleton = NULL;

	/**
	 * Ritorna una istanza globale di questo model.
	 * @return mixed La istanza globale.
	 */
	public static function getInstance()
	{
		if(self::$singleton == NULL)
			self::$singleton = new Cliente();
		return self::$singleton;
	}

	/*
	 * Specifiche attributi del tipo del Model rappresentato da questa classe
	 */
	public $attribTableName = "Cliente";
	public $attribLabel = "Ragsoc";
	public $attribNames = array(STD_ID, "idAgente", "Ragsoc", "Indirizzo", "CAP", "Citta", "Provincia",
		"Stato", "Telefono", "Cellulare", "Fax", "E_MailCommerciale", "E_MailTecnico", "E_MailAmministrativo", "E_MailPec", "SitoWeb", "Referente", "CodiceRifDitta",
		"TipoCliente", "CodiceFiscale", "PartitaIVA", "CondizioniPagamento", "Banca", "IBAN");
	public $attribExcludeFromAdd = array(STD_ID);
	public $attribExcludeFromEdit = array(STD_ID);
	public $attribLongNames = array(STD_ID => "ID", "idAgente" => "Agente impegnato con questo cliente",
		"Ragsoc" => "Ragione sociale", "Indirizzo" => "Indirizzo", "CAP" => "CAP", "Citta" => "Citt&agrave;",
		"Provincia" => "Provincia", "Stato" => "Stato", "Telefono" => "Telefono", "Cellulare" =>"Cellulare",
		"Fax" => "Fax", "E_MailCommerciale" => "E-Mail Commerciale", "E_MailTecnico" => "E-Mail Tecnico",
		"E_MailAmministrativo" => "E-Mail Amministrativo", "E_MailPec" => "E-Mail Pec", "SitoWeb" => "Sito Web",
		"Referente" => "Referente", "CodiceRifDitta" => "Sede Operativa",
		"TipoCliente" => "Tipo Cliente", "CodiceFiscale" => "Codice Fiscale", "PartitaIVA" => "Partita IVA",
		"CondizioniPagamento" => "Condizioni di pagamento standard", "Banca" => "Banca", "IBAN" => "IBAN C&#47;C");
	public $attribIsImportant = array( STD_ID => 2, "idAgente" => 1, "Ragsoc" => 1, "Indirizzo" => 0, "CAP" => 0,
		"Citta" => 1, "Provincia" => 1, "Stato" => 1, "Telefono" => 1, "Cellulare" => 0, "Fax" => 1,
		"E_MailCommerciale" => 0, "E_MailTecnico" => 0, "E_MailAmministrativo" => 0, "E_MailPec" => 0,
		"SitoWeb" => 0, "Referente" => 0, "CodiceRifDitta" => 0, "TipoCliente" => 1, "CodiceFiscale" => 0,
		"PartitaIVA" => 1, "CondizioniPagamento" => 0, "Banca" => 0, "IBAN" => 0);
	public $attribIsNumeric = array( STD_ID => true, "idAgente" => true, "Ragsoc" => false, "Indirizzo" => false,
		"CAP" => false, "Citta" => false, "Provincia" => false, "Stato" => false, "Telefono" => false,
		"Cellulare" => false, "Fax" => false, "E_MailCommerciale" => false, "E_MailTecnico" => false,
		"E_MailAmministrativo" => false, "E_MailPec" => false, "SitoWeb" => false, "Referente" => false,
		"CodiceRifDitta" => false, "TipoCliente" => false, "CodiceFiscale" => false,
		"PartitaIVA" => false, "CondizioniPagamento" => false, "Banca" => false, "IBAN" => false);
	public $attribIsForeignKey = array( STD_ID => false, "idAgente" => "Agenti", "Ragsoc" => false, "Indirizzo" => false,
		"CAP" => false, "Citta" => false, "Provincia" => false, "Stato" => false, "Telefono" => false,
		"Cellulare" => false, "Fax" => false, "E_MailCommerciale" => false, "E_MailTecnico" => false,
		"E_MailAmministrativo" => false, "E_MailPec" => false, "SitoWeb" => false, "Referente" => false,
		"CodiceRifDitta" => false, "TipoCliente" => false, "CodiceFiscale" => false,
		"PartitaIVA" => false, "CondizioniPagamento" => false, "Banca" => false, "IBAN" => false);

	const joinTable = "Cliente LEFT JOIN Agente ON Cliente.idAgente = Agente.ID";
	const joinSelect ="Cliente.*, Agente.Nome, Agente.Cognome";

	/*
	 * Specifiche per gli elementi form associati agli attributi
	 */
	private static $attribHTMLFormValue = array( STD_ID => FORM_HIDDEN, "idAgente" => FORM_EXTERNAL_SELECTOR,
		"Ragsoc" => FORM_TEXT, "Indirizzo" => FORM_TEXT, "CAP" => FORM_TEXT, "Citta" => FORM_TEXT,
		"Provincia" => FORM_TEXT, "Stato" => FORM_TEXT, "Telefono" => FORM_TEXT, "Cellulare" => FORM_TEXT,
		"Fax" => FORM_TEXT, "E_MailCommerciale" => FORM_TEXT, "E_MailTecnico" => FORM_TEXT,
		"E_MailAmministrativo" => FORM_TEXT, "E_MailPec" => FORM_TEXT, "SitoWeb" => FORM_TEXT, "Referente" => FORM_TEXT,
		"CodiceRifDitta" => FORM_TEXT, "TipoCliente" => FORM_LIST, "CodiceFiscale" => FORM_TEXT,
		"PartitaIVA" => FORM_TEXT, "CondizioniPagamento" => FORM_TEXT, "Banca" => FORM_TEXT, "IBAN" => FORM_TEXT);
	private static $attribHTMLFormIsMandatory = array( STD_ID => true, "idAgente" => true, "Ragsoc" => true,
		"Indirizzo" => true, "CAP" => false, "Citta" => false, "Provincia" => false, "Stato" => false,
		"Telefono" => false, "Cellulare" => false, "Fax" => false, "E_MailCommerciale" => false,
		"E_MailTecnico" => false, "E_MailAmministrativo" => false, "E_MailPec" => false, "SitoWeb" => false,
		"Referente" => false, "CodiceRifDitta" => false, "TipoCliente" => false, "CodiceFiscale" => false,
		"PartitaIVA" => true, "CondizioniPagamento" => false, "Banca" => false, "IBAN" => false);
	
	public static $tipoClienteList = array(0 => " ", 1 => "Imprese di impianti", 2 => "Imprese di costruzioni", 3 => "Grossisti", 4 => "Progettisti", 5 => "Installatori", 6 => "Enti", 8 => "Rivenditori", 7 => "Altro");

	/**
	 * Restituisce l'HTML per creare un campo di un form adatto a contenere il
	 * valore dell'attribbuto passato. Questo campo di testo sarà vuoto e dovrà
	 * servire per la creazione di una nuova istanza in DB di questo model.
	 * @param string $attribName Nome dell'attributo su cui creare il campo.
	 * @return string Stringa contenente l'HTML dell'elemento creato.
	 */
	public function getAddFormCodeFromAttribute($db,$attribName)
	{
		if(!isset(self::$attribHTMLFormValue[$attribName]) || $attribName == STD_ID)
			return "";
		switch(self::$attribHTMLFormValue[$attribName])
		{
			case FORM_TEXT: return ModelUtils::getTextFormElement($attribName, "", self::$attribHTMLFormIsMandatory[$attribName]);
			case FORM_EXTERNAL_SELECTOR: return ModelUtils::getExternalSelectorFormElement($attribName, "externalSelector.php", "Agente", "", "", self::$attribHTMLFormIsMandatory[$attribName]);
			case FORM_LIST: return ModelUtils::getListFormElement($attribName, 0, self::$tipoClienteList, self::$attribHTMLFormIsMandatory[$attribName]);
			default: return "";
		}
	}

	/**
	 * Restituisce l'HTML per creare un campo di testo adatto a contenere il
	 * valore dell'attribbuto passato. Questo campo di testo conterrà il valore
	 * attualmente assunto da questo attributo in questa tupla.
	 * @param DatabaseManager $db Database su cui effettuare una possibile
	 * interrogazione.
	 * @param string $attribName Nome dell'attributo di cui creare il codice.
	 * @return string Il codice HTML dell'elemento form corrispondente.
	 */
	public function getEditFormCodeFromAttribute($db, $attribName)
	{
		switch(self::$attribHTMLFormValue[$attribName])
		{
			case FORM_HIDDEN: return ModelUtils::getHiddenFormElement($attribName, $this->dataTupla[$attribName], self::$attribHTMLFormIsMandatory[$attribName]);
			case FORM_TEXT: return ModelUtils::getTextFormElement($attribName, $this->dataTupla[$attribName], self::$attribHTMLFormIsMandatory[$attribName]);
			case FORM_EXTERNAL_SELECTOR: {
				return ($this->getAgente($db) == NULL) ?
						$this->getAddFormCodeFromAttribute($db, $attribName) :
						ModelUtils::getExternalSelectorFormElement($attribName, "externalSelector.php", "Agente", $this->dataTupla[$attribName], $this->getAgente($db)->getLabel(), self::$attribHTMLFormIsMandatory[$attribName]);
			}
			case FORM_LIST: return ModelUtils::getListFormElement($attribName, $this->dataTupla[$attribName], self::$tipoClienteList, self::$attribHTMLFormIsMandatory[$attribName]);
			default: return "";
		}
	}

	/**
	 * Costruttore che acquisisce l'array dei valori associativi.
	 * @param type $data L'array associativo a cui inizializzare questa istanza.
	 */
	public function __construct($data = NULL)
	{
		parent::__construct($data);
	}

	/**
	 * Crea una nuova istanza della sottoclasse specializzante.
	 * @param array $data I dati passati da cui recuperare i valori.
	 * @return mixed Una nuova instanza della sottoclasse specializzante.
	 */
	public function createNew($data)
	{
		$res = new Cliente($data);
		//se l'array contiene già le informazioni sull'agente lo si crea direttamente anch'esso
		if(isset($data["Nome"]) && isset($data["Cognome"]) && isset($data["idAgente"]))
		{
			$agenteData = array();
			$agenteData[STD_ID] = $data["idAgente"];
			$agenteData["Nome"] = $data["Nome"];
			$agenteData["Cognome"] = $data["Cognome"];
			$res->chachedAgente = Agente::getInstance()->createNew($agenteData);
		}
		return $res;
	}

	/**
	 * Metodo che restituisce una etichetta che rappresenta il valore di un
	 * attributo: nella sua versione di default ritorna esattamente il valore
	 * associato a quell'attributo, ma è possibile implementarlo nelle
	 * sottoclassi per specificare opportuni comportamenti, come ad esempio di
	 * non far stampare un numero che rappresenta una chiave esterna, ma invece
	 * una etichetta della tupla ad essa associata.
	 * @param DatabaseManager $db Database su cui poter effettuare una possibile
	 * interrogazione.
	 * @param string $attrib Attributo di cui stampare l'etichetta del valore.
	 * @return string Il valore associato all'attributo o NULL se l'attributo
	 * non è stato trovato.
	 */
	public function getDataLabel($db, $attrib)
	{
		if($attrib == "idAgente")
			return $this->getAgente($db) == NULL ? "" : $this->getAgente($db)->getLabel();
		elseif($attrib == "TipoCliente")
			return $this->dataTupla[$attrib] < 0 || $this->dataTupla[$attrib] > 8 ? "Sconosciuto" : self::$tipoClienteList[$this->dataTupla[$attrib]];
		return parent::getDataLabel($db, $attrib);
	}

	private $chachedAgente = NULL;

	/**
	 * Ritorna una istanza di Agente corrispondente alla chiave esterna
	 * "idAgente" di questa tupla.
	 * @param DatabaseManager $db Database da interrogare.
	 * @return Agente L'instanza creata o NULL in caso di errore.
	 */
	public function getAgente($db)
	{
		$idag = isset($this->dataTupla["idAgente"]) ? $this->dataTupla["idAgente"] : NULL;
		if($idag != NULL && $idag > 0)
		{
			if($this->chachedAgente == NULL || $this->chachedAgente->dataTupla[STD_ID] != $idag)
			{
				$this->chachedAgente = Agente::getInstance()->getFromDB($db, $this->dataTupla["idAgente"]);
				return $this->chachedAgente;
			}
			else
				return $this->chachedAgente;
		}
		return NULL;
	}

	/**
	 * Carica dal DB una lista di istanze di questa sottoclasse caricate con i
	 * valori delle tuple trovate secondo le specifiche passate.
	 * @param DatabaseManager $db Database da cui prelevare le tuple.
	 * @param int $limitMin Limite basso da cui iniziare a prelevare tuple, o
	 * NULL per non usare i limiti.
	 * @param int $limitMax Limite alto a cui fermarsi di prelevare tuple, o
	 * NULL per non usare i limiti.
	 * @param string $orderBy Ordinamento con cui prelevare le tuple, o "" per
	 * non usare alcun ordinamento.
	 * @return array L'array delle nuove istanze create a partire dai valori
	 * trovati nel DB o NULL nel caso qualcosa sia andato storto.
	 */
	public function getListFromDB($db, $limitMin, $limitMax, $orderBy, $cond = "")
	{
		$limits = ($limitMin === NULL || $limitMax === NULL ? "" : ($limitMin.", ".($limitMax-$limitMin)) );
		//SELECT cliente.*, agente.Nome, agente.Cognome FROM cliente LEFT JOIN agente ON cliente.idAgente = agente.ID
		$rs = $db->EnumerateTableStartExt(self::joinSelect, self::joinTable, $orderBy,$cond,$limits);
		if($rs == FALSE)
			return NULL;
		$retarr = array();
		while($db->EnumerateTableNext($rs))
			$retarr[] = $this->createNew($db->EnumerateTableGetValues($rs));
		return $retarr;
	}

	/**
	 * Cerca una serie di tuple nel DB e ritorna tante istanze della sottoclasse
	 * specializzante, quante sono le rispettive tuple trovate con i rispettivi
	 * valori caricati entro i limiti specificati.
	 * @param DatabaseManager $db Database da cui prelevare le tuple.
	 * @param string $paramName Nome dell'attributo su cui effettuare la
	 * ricerca.
	 * @param string $paramValue Valore che l'attributo deve assumere per
	 * includere la sua rispettiva tupla.
	 * @param int $limitMin Limite basso da cui iniziare a prelevare tuple, o
	 * NULL per non usare i limiti.
	 * @param int $limitMax Limite alto a cui fermarsi di prelevare tuple, o
	 * NULL per non usare i limiti.
	 * @param string $orderBy Ordinamento con cui prelevare le tuple, o "" per
	 * non usare alcun ordinamento.
	 * @return array L'array delle nuove istanze create a partire dai valori
	 * trovati nel DB o NULL nel caso qualcosa sia andato storto.
	 */
	public function searchByParam($db, $paramName, $paramValue, $limitMin, $limitMax, $orderBy)
	{
		if(!isset($this->attribIsNumeric[$paramName]))
			return NULL;
		$limits = ($limitMin === NULL || $limitMax === NULL ? "" : ($limitMin.", ".($limitMax-$limitMin)) );
		$cond = NULL;
		if($paramName == "idAgente")
		{
			//se il parametro della ricerca è idAgente, allora la ricerca si effettua su Nome e Cognome dell'agente
			$cond = "Agente.Nome LIKE '%".ModelUtils::escape_sq_for_SQL($paramValue)."%' OR Agente.Cognome LIKE '%".ModelUtils::escape_sq_for_SQL($paramValue)."%'";
		}
		else
		{
			//caso contrario si effettua sul parametro specificato come di norma
			$paramIsNumeric = $this->attribIsNumeric[$paramName];
			if($paramName == STD_ID)
				$paramName = $this->attribTableName.".".STD_ID;
			$cond = ($paramIsNumeric ? $paramName." = ".$paramValue : $paramName." LIKE '%".ModelUtils::escape_sq_for_SQL($paramValue)."%'");
		}
		$rs = $db->EnumerateTableStartExt(self::joinSelect, self::joinTable, $orderBy, $cond, $limits );
		if($rs == FALSE)
			return NULL;
		$retarr = array();
		while($db->EnumerateTableNext($rs))
			$retarr[] = $this->createNew($db->EnumerateTableGetValues($rs));
		return $retarr;
	}

	/**
	 * Restituiscce il numero di tuple del risultato della ricerca.
	 * @param DatabaseManager $db Database da interrogare.
	 * @param string $searchAttrib Nome dell'attributo su cui effettuare la
	 * ricerca.
	 * @param string $searchVal Valore che l'attributo deve assumere per far
	 * contare la propria tupla.
	 * @return int Restituisce il numero di tuple trovate o FALSE in caso di
	 * errore.
	 */
	public function getRecordsNumOfSearchResult($db,$searchAttrib,$searchVal)
	{
		if(!isset($this->attribIsNumeric[$searchAttrib]))
			return FALSE;
		$cond = NULL;
		if($searchAttrib == "idAgente")
		{
			//se il parametro della ricerca è idAgente, allora la ricerca si effettua su Nome e Cognome dell'agente
			$cond = "Agente.Nome LIKE '%".ModelUtils::escape_sq_for_SQL($searchVal)."%' OR Agente.Cognome LIKE '%".ModelUtils::escape_sq_for_SQL($searchVal)."%'";
		}
		else
		{
			//caso contrario si effettua sul parametro specificato come di norma
			$paramIsNumeric = $this->attribIsNumeric[$searchAttrib];
			if($searchAttrib == STD_ID)
				$searchAttrib = $this->attribTableName.".".STD_ID;
			$cond = ($paramIsNumeric ? $searchAttrib." = ".$searchVal : $searchAttrib." LIKE '%".ModelUtils::escape_sq_for_SQL($searchVal)."%'");
		}
		return $db->GetRecordsNum(self::joinTable,$cond);
	}

}

?>
